#lang rosetta-racket


(require "utils.rkt")

(provide (struct-out volume)
         make-volume
         volume-ref
         volume-set
         volume-set-vals)


(define (volume-print volume port mode)
  (for ((z (: (volume-nz volume))))
    (for ((y (: (volume-ny volume))))
      (for ((x (: (volume-nx volume))))
        (write-string (format "~A" (volume-ref volume x y z)) port))
      (unless (= y (- (volume-ny volume) 1))
        (newline port)))
    (unless (= z (- (volume-nz volume) 1))
      (newline port))))

(struct volume (ns nx ny nz)
  #:constructor-name new-volume
  #:property prop:custom-write volume-print)

(define (make-volume nx ny nz)
  (new-volume (make-vector (* nx ny nz) 0) nx ny nz))

(define (volume-pos volume x y z)
  (let ((nx (volume-nx volume))
        (ny (volume-ny volume)))
    (+ x (* y nx) (* z (* nx ny)))))

(define (volume-ref volume x y z)
  (vector-ref (volume-ns volume) (volume-pos volume x y z)))

(define (volume-set b x y z val)
  (struct-copy volume b (ns (vector-set (volume-ns b) (volume-pos b x y z) val))))

(define (volume-set-vals b xyzs vals)
  (struct-copy volume b (ns (vector-set-vals (volume-ns b) (map (match-lambda ((list x y z) (volume-pos b x y z))) xyzs) vals))))